#pragma once
#include <cpp-httplib/httplib.h>
#include <iostream>
#include <unordered_map>
#include <fstream>
#include "contact.pb.h"
#include "protos/add_contact.pb.h"
#include "protos/del_contact.pb.h"
#include "protos/view_contact_list.pb.h"
#include "protos/view_contact.pb.h"

s_contact::Contacts _contacts; // 存储当前的联系人信息

const std::string filename = "./contacts.bin";

bool initContacts()
{
    std::ifstream input(filename, std::ios::in | std::ios::binary);
    if (!input)
    {
        //文件不存在，则不用初始化
        input.close();
        return true;
    }

    if (_contacts.contacts_size() > 0)
        _contacts.clear_contacts();

    if (!_contacts.ParseFromIstream(&input))
    {
        input.close();
        std::cerr << "Fail to parse contacts from local" << std::endl;
        return false;
    }

    input.close();
    return true;
}

bool storageContacts()
{
    if (_contacts.contacts_size() == 0)
        return true;

    std::ofstream output(filename, std::ios::out | std::ios::trunc | std::ios::binary);
    if (!output)
    {
        std::cerr << "Open file failed" << std::endl;
        output.close();
        return false;
    }

    if(!_contacts.SerializeToOstream(&output))
    {
        std::cerr << "Fail to serialize contacts to local" << std::endl;
        output.close();
        return false;
    }

    output.close();
    return true;
}

std::string buildUid(const add_contact::AddContactRequest &add_req)//TODO
{
    std::string uid = add_req.name();
    uid += '-';
    uid += std::to_string(add_req.age());
    return uid;
}

void addContact(const httplib::Request &req, httplib::Response &resp) // 添加一名新联系人
{
    // 1.从文件读取已存在的联系人信息
    if (!initContacts())
    {
        resp.status = 500;
        resp.reason = "Internal Server Error";
        return;
    }

    // 2.向通讯录中新增联系人

    // 2.1 将请求body反序列化为一个“新增联系人”请求消息对象
    add_contact::AddContactRequest add_req;
    if(!add_req.ParseFromString(req.body))
    {
        std::cerr << "add_req 反序列化失败" << std::endl;
        return;
    }

    // 2.2 通过add_req构造一个服务器的Contact联系人对象
    std::string uid = buildUid(add_req); // TODO生成uid

    s_contact::Contact contact;
    contact.set_uid(uid);
    contact.set_name(add_req.name());
    contact.set_age(add_req.age());
    for (int i = 0; i < add_req.phone_size(); i++)
    {
        auto phone = add_req.phone(i);
        auto new_phone = contact.add_phone();
        new_phone->set_number(phone.number());
        if(phone.type() == add_contact::AddContactRequest_Phone_PhoneType::AddContactRequest_Phone_PhoneType_MOB)
            new_phone->set_type(s_contact::Contact_Phone_PhoneType::Contact_Phone_PhoneType_MOB);
        if(phone.type() == add_contact::AddContactRequest_Phone_PhoneType::AddContactRequest_Phone_PhoneType_TEL)
            new_phone->set_type(s_contact::Contact_Phone_PhoneType::Contact_Phone_PhoneType_TEL);
    }

    // 2.3 将新联系人插入通讯录中
    _contacts.mutable_contacts()->insert({uid, contact});

    // 3.将内存中的通讯录持久化到文件中
    if (!storageContacts())
    {
        // 服务器内部错误
        resp.status = 500;
        resp.reason = "Internal Server Error";
        return;
    }

    // 4.新增联系人成功，返回响应
    add_contact::AddContactResponse add_resp;
    add_resp.set_uid(uid);
    add_resp.mutable_base_resp()->set_success(true);

    // 4.1 序列化响应
    std::string add_resp_str;
    if (!add_resp.SerializeToString(&add_resp_str))
    {
        std::cerr << "add_resp 序列化失败" << std::endl;
        return;
    }

    // 4.2 设置响应
    resp.set_content(add_resp_str, "application/protobuf");
    resp.status = 200;
    resp.reason = "OK";
}

void delContact(const httplib::Request &req, httplib::Response &resp) // 删除一名联系人
{
    // 1.从文件读取已存在的联系人信息
    if (!initContacts())
    {
        resp.status = 500;
        resp.reason = "Internal Server Error";
        return;
    }

    // 2.从请求中获取删除联系人的uid
    del_contact::DelContactRequest del_req;
    if(!del_req.ParseFromString(req.body))
    {
        std::cerr << "del_req 反序列化失败" << std::endl;
        return;
    }
    std::string uid = del_req.uid();

    // 3.删除指定联系人
    auto contacts = _contacts.mutable_contacts();

    if(contacts->erase(uid) == 0)
    {
        //目标联系人不存在
        resp.status = 404;
        resp.reason = "Not Founded";
        return;
    }

    // 4.将内存中的通讯录持久化到文件中
    if (!storageContacts())
    {
        // 服务器内部错误
        resp.status = 500;
        resp.reason = "Internal Server Error";
        return;
    }

    // 5.删除联系人成功，返回响应
    del_contact::DelContactResponse del_resp;
    del_resp.set_uid(uid);
    del_resp.mutable_base_resp()->set_success(true);

    // 5.1 序列化响应
    std::string del_resp_str;
    if (!del_resp.SerializeToString(&del_resp_str))
    {
        std::cerr << "del_resp 序列化失败" << std::endl;
        return;
    }

    // 5.2 设置响应
    resp.set_content(del_resp_str, "application/protobuf");
    resp.status = 200;
    resp.reason = "OK";
}

void viewContactList(const httplib::Request &req, httplib::Response &resp) // 查找并返回联系人列表
{
    // 1.从文件读取已存在的联系人信息
    if (!initContacts())
    {
        resp.status = 500;
        resp.reason = "Internal Server Error";
        return;
    }

    // 2.将通讯录中的联系人信息概要到联系人列表响应中
    view_contact_list::ViewContactListResponse view_list_resp;
    for(auto kv : _contacts.contacts())
    {
        auto info =  view_list_resp.add_contacts();
        info->set_uid(kv.first);
        info->set_name(kv.second.name());
    }
    view_list_resp.mutable_base_resp()->set_success(true);

    // 3.获取联系人列表成功，返回响应
    std::string view_list_resp_str;
    if(!view_list_resp.SerializeToString(&view_list_resp_str))
    {
        std::cerr << "view_list_resp 序列化失败" << std::endl;
        return;
    }

    resp.set_content(view_list_resp_str, "application/protobuf");
    resp.status = 200;
    resp.reason = "OK";
}

void viewContact(const httplib::Request &req, httplib::Response &resp) // 查找一名联系人
{
    // 1.从文件读取已存在的联系人信息
    if (!initContacts())
    {
        resp.status = 500;
        resp.reason = "Internal Server Error";
        return;
    }

    // 2.查找目标联系人
    std::string url = req.path;// --> "/contacts/list/uid"
    std::string uid = url.substr(url.find_last_of('/') + 1);

    const auto& contacts = _contacts.contacts();

    if(contacts.find(uid) == contacts.end())
    {
        //目标联系人不存在
        resp.status = 404;
        resp.reason = "Not Founded";
        return;
    }

    const auto& target = contacts.at(uid);
    view_contact::ViewContactResponse view_one_resp;
    view_one_resp.set_uid(uid);
    view_one_resp.set_name(target.name());
    view_one_resp.set_age(target.age());

    for (int i = 0; i < target.phone_size(); i++)
    {
        auto phone = target.phone(i);
        auto new_phone = view_one_resp.add_phone();
        new_phone->set_number(phone.number());
        if(phone.type() == s_contact::Contact_Phone_PhoneType::Contact_Phone_PhoneType_MOB)
            new_phone->set_type(view_contact::ViewContactResponse_Phone_PhoneType::ViewContactResponse_Phone_PhoneType_MOB);
        if(phone.type() == s_contact::Contact_Phone_PhoneType::Contact_Phone_PhoneType_TEL)
            new_phone->set_type(view_contact::ViewContactResponse_Phone_PhoneType::ViewContactResponse_Phone_PhoneType_TEL);
    }
    view_one_resp.mutable_base_resp()->set_success(true);


    // 3.获取联系人成功，返回响应
    std::string view_one_resp_str;
    if(!view_one_resp.SerializeToString(&view_one_resp_str))
    {
        std::cerr << "view_one_resp 序列化失败" << std::endl;
        return;
    }

    resp.set_content(view_one_resp_str, "application/protobuf");
    resp.status = 200;
    resp.reason = "OK";
}